package com.stylefeng.guns.modular.api;

import cn.hutool.core.date.DateTime;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.stylefeng.guns.core.base.controller.BaseController;
import com.stylefeng.guns.core.base.tips.ErrorTip;
import com.stylefeng.guns.core.cache.CacheKit;
import com.stylefeng.guns.core.common.Tools.Result;
import com.stylefeng.guns.core.common.annotion.BussinessLog;
import com.stylefeng.guns.core.common.exception.BizExceptionEnum;
import com.stylefeng.guns.core.exception.GunsException;
import com.stylefeng.guns.core.shiro.ShiroKit;
import com.stylefeng.guns.core.shiro.ShiroUser;
import com.stylefeng.guns.core.shiro.factory.ShiroFactroy;
import com.stylefeng.guns.core.support.HttpKit;
import com.stylefeng.guns.core.util.JwtTokenUtil;
import com.stylefeng.guns.core.util.ToolUtil;
import com.stylefeng.guns.modular.system.dao.UserCwMapper;
import com.stylefeng.guns.modular.system.model.Function;
import com.stylefeng.guns.modular.system.model.UserCw;
import com.stylefeng.guns.modular.system.service.IFunctionService;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 接口控制器提供
 *
 * @author stylefeng
 * @Date 2018/7/20 23:39
 */
@RestController
@RequestMapping("/gunsApi")
@Api(value="ApiController",tags={"前后端分离登录控制器"})
@Slf4j
public class ApiController extends BaseController {
    
    @Autowired
    private UserCwMapper userCwMapper;
    
    @Autowired
    private IFunctionService functionService;
    
    // 过期时间30分钟
    private static final long EXPIRE_TIME = 30 * 60 * 1000;
    
    
    private static final String CACHE_STRATEGY = "local";
    
    
    /**
     * @Cacheable是向缓存中添加数据,@CacheEvict是删除缓存中数据,@CachePut是更新缓存中数据
     * api登录接口，通过账号密码获取token
     */
    @ApiOperation(value="auth",notes = "用户登录验证",httpMethod ="GET")
    @ApiImplicitParams({ @ApiImplicitParam(paramType = "query", dataType = "String", name = "username", value = "用户登录账号", required = true),
                         @ApiImplicitParam(paramType = "query", dataType = "String", name = "password", value = "用户登录密码", required = true)
    })
    @GetMapping("/auth")
    @CachePut(value=CACHE_STRATEGY,key="'key_'+#username")
    @ResponseBody
    public Object auth(@RequestParam(value="username") String username, @RequestParam(value="password") String password) {
        if(ToolUtil.isOneEmpty(username,password)){
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        
        //封装请求账号密码为shiro可验证的token
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password.toCharArray());
        //获取数据库中的账号密码，准备比对
        UserCw u = new UserCw();
        u.setSuLoginName(username);
        UserCw userCw = userCwMapper.selectOne(u);
        if(userCw==null){
            return new ErrorTip(400, "账号密码错误！");
        }
        int suState=userCw.getSuState();
        if (suState==2){
            return new ErrorTip(300, "该账号被冻结，请连续管理员!");
        }else if(suState==3){
            return new ErrorTip(301, "该账号被删除!");
        }
        
        String credentials = userCw.getSuLoginPwd();
        String salt = userCw.getSuSalt();
        ByteSource credentialsSalt = new Md5Hash(salt);
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                new ShiroUser(), credentials, credentialsSalt, "");

        //校验用户账号密码
        HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher();
        md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.hashAlgorithmName);
        md5CredentialsMatcher.setHashIterations(ShiroKit.hashIterations);
        boolean passwordTrueFlag = md5CredentialsMatcher.doCredentialsMatch(
                usernamePasswordToken, simpleAuthenticationInfo);

        if (passwordTrueFlag) {
            Subject currentUser = ShiroKit.getSubject();
            currentUser.login(usernamePasswordToken);
            // 得到当前执行的用户
            String token=JwtTokenUtil.generateToken(String.valueOf(userCw.getSuId()));
            JSONObject result = JSONUtil.createObj();
            result.put("token",token);
            result.put("user", ShiroFactroy.me().shiroUser(userCw));
            result.put("code","200");
            result.put("message","鉴权成功!");
            ShiroUser shiroUser=ShiroKit.getUser();
            CacheKit.remove(CACHE_STRATEGY,token);
            CacheKit.put(CACHE_STRATEGY,token,shiroUser);
            log.info("用户名为:"+shiroUser.getName()+",所属机构:"+shiroUser.getSoName()+",时间:"+ DateTime.now()+"登陆成功！");
            return result;
        } else {
            log.info("用户名为:"+u.getSuiName()+",所属机构:"+u.getSoId()+",时间:"+ DateTime.now()+"登陆失败,账号密码错误！");
            return new ErrorTip(400, "账号密码错误！");
        }
    }
    
    
    @ApiOperation(value="getFunList",notes = "登录用户菜单列表获取(用户角色和岗位权限集)",httpMethod ="GET")
    @GetMapping("/getFunList")
    @CachePut(value=CACHE_STRATEGY,key="'key_functionCache'+#flag")
    @ResponseBody
    public Result getFunctionList(@ApiParam(name = "flag", value = "是否过滤(0:不过滤菜单 1:过滤菜单)", required = true)  @RequestParam(value="flag",required = true) Integer flag){
        //完善pids,根据pid拿到pid的pids
        String token= HttpKit.getRequest().getHeader("Authorization").substring(7);
        String subject = JwtTokenUtil.getClaimFromToken(token).getSubject();//用户ID
        UserCw user=null;
        ShiroUser shiroUser=null;
        if(StringUtils.isNotEmpty(subject)){
             user=this.userCwMapper.selectById(subject);
             shiroUser= ShiroFactroy.me().shiroUser(user);
        }
        List<String> roleIds=shiroUser.getRoleList();//角色ID集
        Integer postId=shiroUser.getSpId();//主岗位ID
        List<Integer> postIds=shiroUser.getSupId();//兼职岗位ID集
        
        List<Integer> pList=new ArrayList();//岗位集
        List<Function> functionList = new ArrayList<>();
        if(ToolUtil.isNotEmpty(postId))
            pList.add(0,postId);
        if(ToolUtil.isNotEmpty(postIds))
            pList.addAll(postIds);
        //去除重复项(主岗:副岗重复)
        pList= pList.stream().distinct().collect(Collectors.toList());
        
        if (!roleIds.isEmpty()) {
            List<Function> rList=this.functionService.getMenusByRoleIds(roleIds,flag);
            functionList.addAll(rList);
        }
        if(ToolUtil.isNotEmpty(pList)){
            List<Function> fList=this.functionService.getMenusByPostIds(pList,flag);
            functionList.addAll(fList);
        }
        //根据ID去重
        List<Function> distinctClass = functionList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<Function>(Comparator.comparing(o -> o.getSfId()))), ArrayList::new));
        //根据ID排序
        Collections.sort(distinctClass, Comparator.comparing(Function::getSfId));
        return Result.success(distinctClass);
    }
    /**
     * 测试接口是否走鉴权
     */
    @RequestMapping(value = "/test", method = RequestMethod.POST)
    public Object test() {
        return SUCCESS_TIP;
    }

}

